/*
 * Copyright (C) 2009 James Ancona
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.android.maps;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import android.R.integer;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.MediaStore.Video;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewManager;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ZoomControls;

import cn.zy.tools.Utils;

import com.commonsware.cwac.bus.SimpleBus;
import com.commonsware.cwac.cache.AsyncCache;
import com.commonsware.cwac.cache.WebImageCache;
import com.commonsware.cwac.cache.ZoomCache;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.MillionsPixels.R;

/**
 * {@hide}
 * 
 * @author Jim Ancona
 */
public class MapView extends ViewGroup implements ViewManager, ViewParent,
		Drawable.Callback, KeyEvent.Callback {
	private static final int MAX_CACHE_SIZE = 50;
	private static final int ONE_WEEK_IN_MILLIS = 1000 * 60 * 60 * 24 * 7;
	private static final String TAG = "MapView";
	private MapSourceInfo mapSourceInfo = new CloudmadeSourceInfo(
			"b06a3135a4eb5848a225483969f56967");
	private int tileSize = mapSourceInfo.getTileSize();
	private GeoPoint center;
	private int zoomLevel = 1;
	private int width, height;
	private List<Overlay> overlays = new ArrayList<Overlay>();
	private WebImageCache cache;
	private Drawable placeholder;
	private SimpleBus bus = new SimpleBus();
	private AsyncCache.DiskCachePolicy policy = new AsyncCache.DiskCachePolicy() {
		public boolean eject(File file) {
			return (System.currentTimeMillis() - file.lastModified() > ONE_WEEK_IN_MILLIS);
		}
	};
	private ZoomControls zoomControls = new ZoomControls(getContext());
	private int touchDownX;
	private int touchDownY;
	private Stack<ImageView> extraImages = new Stack<ImageView>();
	private TextView creditsView = new TextView(getContext());

	int[] oneWh = new int[2];
	int[] curXYCount = new int[2];
	int[] commonWh = new int[2];
	int[] WH = new int[2];
	static int[] offset = new int[2];

	public MapView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context, attrs);
	}

	public MapView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public MapView(Context context, String apiKey) {
		super(context);
		init(context, null);
	}

	private void willScale(int zoomLevel1) {

		// 用于缓冲放大，和缩小的处理图片
		int tZoomLevel = zoomLevel1;
		GeoPoint tCenter = center;
		int tTouchDownX = touchDownX;
		int tTouchDownY = touchDownY;
		int[] tCurXYCount = curXYCount;
		int[] tWH = WH;

		// 计算下级的目录
		if (zoomLevel != zoomLevel1 && zoomLevel >= 1
				&& zoomLevel <= getMaxZoomLevel()) {
			int lat = 0;
			int longi = 0;
			// int levelOffset=Math.abs(zoomLevel1-this.zoomLevel);
			int count = 2;
			if ((zoomLevel1 - this.zoomLevel) > 0) {

				lat = center.getLatitudeE6() * count;
				longi = center.getLongitudeE6() * count;
				touchDownX = touchDownX * count;
				touchDownY = touchDownY * count;

			} else {

				lat = center.getLatitudeE6() / count;
				longi = center.getLongitudeE6() / count;
				touchDownX = touchDownX / count;
				touchDownY = touchDownY / count;

			}
			Log.e(center.getLatitudeE6() + "tag" + center.getLongitudeE6(), lat
					+ "***" + longi + "**" + touchDownX + "***" + touchDownY);

			this.center = new GeoPoint(lat, longi);

			MapView.getCurScaleLevelRect(curXYCount, zoomLevel1);
			getCurScaleLevelWh(WH, zoomLevel1);

			Log.e("----tag---", "zoomLevel1");

		}

		// 开始计算要用处理的放大或缩小的图片

		int[] commonXY = new int[2];
		getCurScaleLevelRect(commonXY, zoomLevel);

		InternalProjection p = (InternalProjection) getProjection();
		GeoPoint viewTopLeft = p.fromPixels(0, 0);
		TileCoords topLeftTile = p.getTileCoords(viewTopLeft);
		GeoPoint viewBottomRight = p.fromPixels(width - 1, height - 1);
		TileCoords bottomRightTile = p.getTileCoords(viewBottomRight);
		TileCoords centerTile = p.getTileCoords(center);

		Point centerTileOffset = p.geoPointToPoint(center);
		// centerTileOffset.x -= (centerTile.getX() * tileSize);
		// centerTileOffset.y -= (centerTile.getY() * tileSize);

		centerTileOffset.x = (getWidth() / 2 - (center.getLatitudeE6() - (centerTile
				.getY() - 1) * tileSize));
		centerTileOffset.y = (getHeight() / 2 - (center.getLongitudeE6() - (centerTile
				.getX() - 1) * tileSize));
		// Log.e("----top----", topLeftTile.getX() + "*" + topLeftTile.getY());
		//
		// Log.e("----center----",
		// centerTile.toString() + "*"+"bottom" + bottomRightTile.getX() + "***"
		// + bottomRightTile.getY());

		int index = 0;
		boolean zoomDisplayed = false;

		for (int tileX = Math.max(topLeftTile.getX(), 0); tileX <= Math.min(
				bottomRightTile.getX(), commonXY[1]); tileX++) {
			for (int tileY = Math.max(topLeftTile.getY(), 0); tileY <= Math
					.min(bottomRightTile.getY(), commonXY[0]); tileY++) {
				ImageView image = null;
				while (index < getChildCount() && image == null) {
					View v = getChildAt(index++);
					if (v instanceof ImageView)
						image = (ImageView) v;
					else if (v.equals(zoomControls))
						zoomDisplayed = true;
				}

				if (index >= getChildCount() && image == null) {
					image = getImageView();
					//addView(image);
					index++;
				}

				try {
					getCache().handleImageView(image,
							mapSourceInfo.getTileUri(tileX, tileY, zoomLevel),
							"Maps");
				} catch (Exception e) {
					throw new RuntimeException(
							"Caught exception retrieving image: ", e);
				}

				int leftPadding = (tileY - centerTile.getY()) * tileSize
						+ centerTileOffset.x;
				int topPadding = (tileX - centerTile.getX()) * tileSize
						+ centerTileOffset.y;

//				Log.e("tag", leftPadding + "*" + "*" + topPadding + "\n"
//						+ tileX + "*" + tileY + "****" + centerTileOffset.x
//						+ "--------" + offset[0] + "\\" + offset[1]);

				boolean hasLayout = false;
				if (tileY == curXYCount[0]) {
					if (tileX == curXYCount[1]) {
						image.layout(leftPadding, topPadding, leftPadding
								+ offset[0], topPadding + offset[1]);
					} else {
						image.layout(leftPadding, topPadding, leftPadding
								+ offset[0], topPadding + tileSize);
					}
					Log.e("tag", "---------------1" + offset[0] + "**"
							+ offset[1]);

					hasLayout = true;

				} else if (tileX == curXYCount[1]) {
					if (tileY == 1) {
						image.layout(leftPadding, topPadding, leftPadding
								+ tileSize, topPadding + offset[1]);
					} else if (tileY == curXYCount[0]) {
						image.layout(leftPadding, topPadding, leftPadding
								+ offset[0], topPadding + offset[1]);
					} else {
						image.layout(leftPadding, topPadding, leftPadding
								+ tileSize, topPadding + offset[1]);

						Log.e("tag", "---------------2");

					}

					hasLayout = true;
				}
				if (hasLayout == false) {
					image.layout(leftPadding, topPadding, leftPadding
							+ tileSize, topPadding + tileSize);
				}

				// image.layout(leftPadding, topPadding, leftPadding
				// + tileSize, topPadding + tileSize);

			}
		}

	}

	private void init(Context context, AttributeSet attrs) {

		getOneLevelWH(oneWh);
		MapView.getCurScaleLevelRect(curXYCount, zoomLevel);
		commonWh[0] = 512;
		commonWh[1] = 512;

		getCurScaleLevelWh(WH, zoomLevel);
		center = new GeoPoint(WH[0] / 2, WH[1] / 2);

		// center = getProjection().fromPixels(width / 2, height / 2);
		// Log.e(TAG, "center" + center.toString());

		// getProjection().
		// GeoPoint newCenter = getProjection().fromPixels(width / 2, height /
		// 2);

		placeholder = getResources().getDrawable(R.drawable.blank_tile);
		zoomControls.setLayoutParams(new LayoutParams(
				android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
				android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
		zoomControls.setOnZoomOutClickListener(new OnClickListener() {
			public void onClick(View v) {
				willScale(zoomLevel - 1);
				setZoomLevel(zoomLevel - 1);
				checkZoomControl();
				invalidate();
			}
		});
		zoomControls.setOnZoomInClickListener(new OnClickListener() {
			public void onClick(View v) {

				willScale(zoomLevel + 1);
				setZoomLevel(zoomLevel + 1);
				checkZoomControl();
				invalidate();
			}
		});
		zoomControls.setVisibility(View.VISIBLE);
		zoomControls.measure(android.view.View.MeasureSpec.UNSPECIFIED,
				android.view.View.MeasureSpec.UNSPECIFIED);
		creditsView.setText(mapSourceInfo.getAttribution());
		creditsView.setTextColor(Color.BLACK);
		creditsView.setBackgroundColor(R.color.transparent);
		// Use smaller than default text size
		creditsView.setTextSize(creditsView.getTextSize() * 0.75f);
		creditsView.setGravity(Gravity.TOP | Gravity.RIGHT);
		creditsView.setVisibility(View.VISIBLE);
		creditsView.measure(android.view.View.MeasureSpec.UNSPECIFIED,
				android.view.View.MeasureSpec.UNSPECIFIED);
		addView(creditsView);
	}

	void checkZoomControl() {
		zoomControls.setIsZoomOutEnabled(zoomLevel > 0);
		zoomControls.setIsZoomInEnabled(zoomLevel < getMaxZoomLevel());

	}

	private synchronized WebImageCache getCache() {
		if (cache == null) {
			cache = new WebImageCache(getContext().getCacheDir(), bus, policy,
					MAX_CACHE_SIZE, placeholder);
		}
		return cache;
	}

	public boolean canCoverCenter() {
		throw new NotImplementedException();
	}

	@Override
	public void computeScroll() {
	}

	public void displayZoomControls(boolean takeFocus) {
		addView(zoomControls);
		if (takeFocus)
			requestChildFocus(zoomControls, zoomControls);
	}

	@Override
	public android.view.ViewGroup.LayoutParams generateLayoutParams(
			AttributeSet attrs) {
		throw new NotImplementedException();
	}

	public MapController getController() {
		return new MapController(this);
	}

	void setMapCenter(GeoPoint center) {
		this.center = center;
		invalidate();
	}

	public GeoPoint getMapCenter() {
		return center;
	}

	public int getMaxZoomLevel() {
		return mapSourceInfo.getMaxZoom();
	}

	public final List<Overlay> getOverlays() {
		return overlays;
	}

	public Projection getProjection() {
		return new InternalProjection();
	}

	@Deprecated
	public View getZoomControls() {
		return zoomControls;
	}

	public void setBuiltInZoomControls(boolean on) {
		if (on)
			addView(zoomControls);
		else
			removeView(zoomControls);
	}

	boolean zoomIn() {
		return setZoomLevel(zoomLevel + 1);
	}

	boolean zoomOut() {
		return setZoomLevel(zoomLevel - 1);
	}

	boolean setZoomLevel(int zoomLevel) {

		if (zoomLevel < 1)
			this.zoomLevel = 1;
		else if (zoomLevel > getMaxZoomLevel())
			zoomLevel = getMaxZoomLevel();
		else
			this.zoomLevel = zoomLevel;
		return this.zoomLevel == zoomLevel;
	}

	public int getZoomLevel() {
		return zoomLevel;
	}

	public boolean isSatellite() {
		return false;
	}

	public boolean isStreetView() {
		return false;
	}

	public boolean isTraffic() {
		return false;
	}

	@Override
	public void onFocusChanged(boolean hasFocus, int direction,
			Rect previouslyFocusedRect) {
		super.onFocusChanged(hasFocus, direction, previouslyFocusedRect);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		return super.onKeyDown(keyCode, event);
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		return super.onKeyUp(keyCode, event);
	}

	public void onRestoreInstanceState(Bundle state) {
	}

	public void onSaveInstanceState(Bundle state) {
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		width = w;
		height = h;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		GeoPoint newCenter;
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			touchDownX = (int) event.getX();
			touchDownY = (int) event.getY();
			return true;
		case MotionEvent.ACTION_MOVE:
			newCenter = getProjection().fromPixels(
					width / 2 - (int) (event.getX() - touchDownX),
					height / 2 - (int) (event.getY() - touchDownY));
			touchDownX = (int) event.getX();
			touchDownY = (int) event.getY();

			setMapCenter(newCenter); // Calls invalidate
			return true;
		case MotionEvent.ACTION_UP:
			newCenter = getProjection().fromPixels(
					width / 2 - (int) (event.getX() - touchDownX),
					height / 2 - (int) (event.getY() - touchDownY));
			setMapCenter(newCenter); // Calls invalidate
		}

		return super.onTouchEvent(event);
	}

	@Override
	public boolean onTrackballEvent(MotionEvent event) {
		return super.onTrackballEvent(event);
	}

	@Override
	public void onWindowFocusChanged(boolean hasFocus) {
		super.onWindowFocusChanged(hasFocus);
	}

	public void preLoad() {
	}

	public void setReticleDrawMode(ReticleDrawMode mode) {
	}

	@Override
	protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {
		return p instanceof MapView.LayoutParams;
	}

	@Override
	protected LayoutParams generateDefaultLayoutParams() {
		return new LayoutParams(
				android.view.ViewGroup.LayoutParams.FILL_PARENT,
				android.view.ViewGroup.LayoutParams.FILL_PARENT);
	}

	@Override
	protected android.view.ViewGroup.LayoutParams generateLayoutParams(
			android.view.ViewGroup.LayoutParams p) {
		return new LayoutParams(p.width, p.height);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(resolveSize(width, widthMeasureSpec),
				resolveSize(height, heightMeasureSpec));
		// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
	}

	private void zoomScale(int curLevel, int nextLevel) {

	}

	@Override
	protected void dispatchDraw(Canvas canvas) {

		int[] commonXY = new int[2];
		getCurScaleLevelRect(commonXY, zoomLevel);

		InternalProjection p = (InternalProjection) getProjection();
		GeoPoint viewTopLeft = p.fromPixels(0, 0);
		TileCoords topLeftTile = p.getTileCoords(viewTopLeft);
		GeoPoint viewBottomRight = p.fromPixels(width - 1, height - 1);
		TileCoords bottomRightTile = p.getTileCoords(viewBottomRight);
		TileCoords centerTile = p.getTileCoords(center);

		Point centerTileOffset = p.geoPointToPoint(center);
		// centerTileOffset.x -= (centerTile.getX() * tileSize);
		// centerTileOffset.y -= (centerTile.getY() * tileSize);

		centerTileOffset.x = (getWidth() / 2 - (center.getLatitudeE6() - (centerTile
				.getY() - 1) * tileSize));
		centerTileOffset.y = (getHeight() / 2 - (center.getLongitudeE6() - (centerTile
				.getX() - 1) * tileSize));
		// Log.e("----top----", topLeftTile.getX() + "*" + topLeftTile.getY());
		//
		// Log.e("----center----",
		// centerTile.toString() + "*"+"bottom" + bottomRightTile.getX() + "***"
		// + bottomRightTile.getY());

		int index = 0;
		boolean zoomDisplayed = false;

		for (int tileX = Math.max(topLeftTile.getX(), 0); tileX <= Math.min(
				bottomRightTile.getX(), commonXY[1]); tileX++) {
			for (int tileY = Math.max(topLeftTile.getY(), 0); tileY <= Math
					.min(bottomRightTile.getY(), commonXY[0]); tileY++) {
				ImageView image = null;
				while (index < getChildCount() && image == null) {
					View v = getChildAt(index++);
					if (v instanceof ImageView)
						image = (ImageView) v;
					else if (v.equals(zoomControls))
						zoomDisplayed = true;
				}

				if (index >= getChildCount() && image == null) {
					image = getImageView();
					addView(image);
					index++;
				}

				try {
					getCache().handleImageView(image,
							mapSourceInfo.getTileUri(tileX, tileY, zoomLevel),
							"Maps");
				} catch (Exception e) {
					throw new RuntimeException(
							"Caught exception retrieving image: ", e);
				}

				int leftPadding = (tileY - centerTile.getY()) * tileSize
						+ centerTileOffset.x;

				// if(tileY == Math.max(topLeftTile.getY(), 0) &&
				// centerTile.getY()==tileY)
				// {
				// leftPadding=-WH[0]/2+getWidth()/2;
				// }
				int topPadding = (tileX - centerTile.getX()) * tileSize
						+ centerTileOffset.y;

				Log.e("tag", leftPadding + "*" + "*" + topPadding + "\n"
						+ tileX + "*" + tileY + "****" + centerTileOffset.x
						+ "--------" + offset[0] + "\\" + offset[1]);

				boolean hasLayout = false;
				if (tileY == curXYCount[0]) {
					if (tileX == curXYCount[1]) {
						image.layout(leftPadding, topPadding, leftPadding
								+ offset[0], topPadding + offset[1]);
					} else {
						image.layout(leftPadding, topPadding, leftPadding
								+ offset[0], topPadding + tileSize);
					}
					Log.e("tag", "---------------1" + offset[0] + "**"
							+ offset[1]);

					hasLayout = true;

				} else if (tileX == curXYCount[1]) {
					if (tileY == 1) {
						image.layout(leftPadding, topPadding, leftPadding
								+ tileSize, topPadding + offset[1]);
					} else if (tileY == curXYCount[0]) {
						image.layout(leftPadding, topPadding, leftPadding
								+ offset[0], topPadding + offset[1]);
					} else {
						image.layout(leftPadding, topPadding, leftPadding
								+ tileSize, topPadding + offset[1]);

						Log.e("tag", "---------------2");

					}

					hasLayout = true;
				}
				if (hasLayout == false) {
					image.layout(leftPadding, topPadding, leftPadding
							+ tileSize, topPadding + tileSize);
				}

				// image.layout(leftPadding, topPadding, leftPadding
				// + tileSize, topPadding + tileSize);

			}
		}

		for (int i = index; i < getChildCount(); i++) {
			View v = getChildAt(i);
			if (v instanceof ImageView)
				removeImageViewAt(i);
			else if (v.equals(zoomControls))
				zoomDisplayed = true;
		}
		creditsView.setVisibility(View.VISIBLE);
		bringChildToFront(creditsView);
		creditsView.layout((width - creditsView.getMeasuredWidth()), 0, width,
				creditsView.getMeasuredHeight());

		if (zoomDisplayed) {
			zoomControls.setVisibility(View.VISIBLE);
			bringChildToFront(zoomControls);
			zoomControls.layout((width - zoomControls.getMeasuredWidth()) / 2,
					height - zoomControls.getMeasuredHeight(),
					(width + zoomControls.getMeasuredWidth()) / 2, height);
		}

		super.dispatchDraw(canvas);
	}

	public void getOneLevelWH(int[] wh) {
		wh[0] = 402 + 512;
		wh[1] = 332;
	}

	public void getCurScaleLevelWh(int[] xyCount, int scaleLevel) {

		int tCount = 1;
		int lastWidth = 1;
		while (tCount <= scaleLevel) {
			if (lastWidth > 1)
				lastWidth = 2 * lastWidth;
			tCount++;
		}
		xyCount[0] = lastWidth == 1 ? oneWh[0] : lastWidth * oneWh[0];

		tCount = 1;
		lastWidth = 1;
		while (tCount <= scaleLevel) {
			if (lastWidth > 1)
				lastWidth = 2 * lastWidth;
			tCount++;
		}

		xyCount[1] = lastWidth == 0 ? oneWh[1] : lastWidth * oneWh[1];

	}

	public static void getCurScaleLevelRect(int[] xyCount, int scaleLevel) {
		switch (scaleLevel) {
		case 1: {
			// 获取两张
			xyCount[0] = 2;
			xyCount[1] = 1;

			offset[0] = 402;
			offset[1] = 322;
		}
			break;
		case 2: {
			xyCount[0] = 4;
			xyCount[1] = 2;

			offset[0] = 292;
			offset[1] = 132;
		}
			break;
		case 3: {
			xyCount[0] = 8;
			xyCount[1] = 3;

			offset[0] = 71;
			offset[1] = 264;
		}
			break;
		case 4: {
			xyCount[0] = 15;
			xyCount[1] = 6;

			offset[0] = 142;
			offset[1] = 15;
		}
			break;
		case 5: {
			xyCount[0] = 29;
			xyCount[1] = 11;

			offset[0] = 283;
			offset[1] = 30;
		}
			break;
		case 6: {
			xyCount[0] = 58;
			xyCount[1] = 21;

			offset[0] = 53;
			offset[1] = 60;
		}
			break;

		default:
			break;
		}
	}

	private void removeImageViewAt(int i) {
		extraImages.push((ImageView) getChildAt(i));
		removeViewAt(i);
	}

	private ImageView getImageView() {
		if (extraImages.isEmpty()) {
			return new ImageView(getContext());
		} else {
			return extraImages.pop();
		}
	}

	public static enum ReticleDrawMode {
		DRAW_RETICLE_NEVER, DRAW_RETICLE_OVER, DRAW_RETICLE_UNDER
	}

	public static class LayoutParams extends ViewGroup.LayoutParams {
		public static final int MODE_MAP = 0;
		public static final int MODE_VIEW = 1;
		public static final int LEFT = 3;
		public static final int RIGHT = 5;
		public static final int TOP = 48;
		public static final int BOTTOM = 80;
		public static final int CENTER_HORIZONTAL = 1;
		public static final int CENTER_VERTICAL = 16;
		public static final int CENTER = 17;
		public static final int TOP_LEFT = 51;
		public static final int BOTTOM_CENTER = 81;

		public int mode;
		public GeoPoint point;
		public int x;
		public int y;
		public int alignment;

		public LayoutParams(int width, int height, GeoPoint point, int alignment) {
			super(width, height);
		}

		public LayoutParams(int width, int height, GeoPoint point, int x,
				int y, int alignment) {
			super(width, height);
		}

		public LayoutParams(int width, int height, int x, int y, int alignment) {
			super(width, height);
		}

		public LayoutParams(int width, int height) {
			super(width, height);
		}

		public LayoutParams(ViewGroup.LayoutParams source) {
			super(source);
		}
	}

	private class InternalProjection implements Projection {
		private static final double CIRCUMFERENCE_IN_METERS = 40075160.0;
		private int tiles = 1 << zoomLevel;
		private double circumference = tileSize * tiles;
		private double radius = circumference / (2.0 * Math.PI);

		Point geoPointToPoint(GeoPoint gp) {
			Point ret = new Point();
			// double longitude = ((double) gp.getLongitudeE6()) / 1000000.0
			// * Math.PI / 180.0;
			// ret.x = (int) (radius * longitude + (circumference / 2.0));
			// double latitude = ((double) gp.getLatitudeE6()) / 1000000.0
			// * Math.PI / 180.0;
			// ret.y = (int) ((circumference / 2.0) - (radius / 2.0 * Math
			// .log((1.0 + Math.sin(latitude))
			// / (1.0 - Math.sin(latitude)))));
			// return ret;

			// GeoPoint c = new GeoPoint(center.getLatitudeE6(),
			// center.getLongitudeE6());
			// ret.x = c.getLatitudeE6() - gp.getLatitudeE6() + getWidth() / 2;
			// ret.y = c.getLongitudeE6() - gp.getLongitudeE6() + getHeight() /
			// 2;
			ret.x = getWidth() / 2;
			ret.y = getHeight() / 2;
			return ret;

		}

		public GeoPoint pointToGeoPoint(Point p) {
			// double longRadians = (p.x - (circumference / 2.0)) / radius;
			// double longDegrees = longRadians * 180.0 / Math.PI;
			// int long1E6 = (int) (longDegrees * 1000000.0);
			//
			// double latitude = (Math.PI / 2.0)
			// - (2.0 * Math.atan(Math
			// .exp(/* -1.0 * */(p.y - (circumference / 2.0))
			// / radius)));
			// int lat1E6 = (int) (latitude * 180.0 / Math.PI * 1000000.0);
			// getCurScaleLevelWh(WH, zoomLevel);
			int long1E6 = center.getLongitudeE6() + p.y;
			int lat1E6 = center.getLatitudeE6() + p.x;

			return new GeoPoint(lat1E6, long1E6);
		}

		public GeoPoint fromPixels(int x, int y) {
			Point c = geoPointToPoint(center);
			c.x = c.x - getWidth() + x;
			c.y = c.y - getHeight() + y;
			return pointToGeoPoint(c);
		}

		public float metersToEquatorPixels(float meters) {
			return (float) (meters * circumference / CIRCUMFERENCE_IN_METERS);
		}

		public Point toPixels(GeoPoint in, Point out) {
			if (out == null)
				out = new Point();
			Point p = geoPointToPoint(in);
			Point c = geoPointToPoint(center);
			out.set(p.x - c.x + (getWidth() / 2), p.y - c.y + (getHeight() / 2));
			return out;
		}

		TileCoords getTileCoords(final int latE6, final int lonE6) {
			// final double lat = ((double) latE6) / 1000000.0;
			// final double lon = ((double) lonE6) / 1000000.0;
			// final long z = (1L << zoomLevel);
			// int xtile = (int) Math.floor((lon + 180.0) / 360.0 * z);
			// int ytile = (int) Math.floor((1.0 - Math.log(Math.tan(lat *
			// Math.PI
			// / 180.0)
			// + 1.0 / Math.cos(lat * Math.PI / 180.0))
			// / Math.PI)
			// / 2 * z);
			int xtile = 0;
			int ytile = 0;
			int width = 0;
			int index = 0;
			for (int x = 0; x < curXYCount[0]; x++) {
				width += commonWh[0];
				index++;
				if (width >= latE6) {
					break;
				}

			}
			ytile = index;

			width = 0;
			index = 0;
			for (int y = 0; y < curXYCount[1]; y++) {
				width += commonWh[1];
				index++;
				if (width >= lonE6) {
					break;
				}

			}
			xtile = index;

			return new TileCoords(xtile, ytile, zoomLevel);
		}

		TileCoords getTileCoords(final GeoPoint gp) {
			return getTileCoords(gp.getLatitudeE6(), gp.getLongitudeE6());
		}

		@SuppressWarnings("unused")
		GeoPoint tileCoordsToGeoPoint(TileCoords osmTile) {
			double n = Math.PI - 2.0 * Math.PI * osmTile.getY() / tiles;
			return new GeoPoint((int) Math.round(180000000.0 / Math.PI
					* Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))),
					(int) (osmTile.getX() * 360000000L / tiles - 180000000L));
		}
	}

}
